package cc.shacocloud.kotlin.tools.cli

import cc.shacocloud.kotlin.tools.Slf4j
import cc.shacocloud.kotlin.tools.cli.MavenRepository.Companion.toRemoteRepository
import cc.shacocloud.kotlin.tools.cli.RunKotlinScript.evalFile
import cc.shacocloud.kotlin.tools.uitls.pathNormalize
import picocli.CommandLine.Command
import picocli.CommandLine.Option
import java.io.File
import kotlin.script.experimental.api.ResultValue
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptDiagnostic


/**
 *
 * @author 思追(shaco)
 */
@Slf4j
@Command(name = "runKotlinScript", mixinStandardHelpOptions = true)
class RunKotlinScriptRunnable(

    /**
     * 内部依赖文件
     */
    val libsDir: File

) : Runnable {

    /**
     * 脚本文件的路径
     */
    @Option(names = ["-s", "--script"], description = ["脚本文件的绝对路径"], required = true)
    lateinit var script: String

    /**
     * 脚本依赖文件地址
     */
    @Option(names = ["-l", "--lib"], description = ["脚本文件的额外依赖路径，只支持绝对路径"])
    var libs: Array<String> = emptyArray()


    /**
     * 脚本依赖文件地址
     */
    @Option(
        names = ["-a", "--artifacts"],
        description = ["脚本文件的依赖的maven库，将从指定的存储库进行下载，格式：<groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>"]
    )
    var artifacts: Array<String> = emptyArray()

    /**
     * 脚本依赖文件地址
     */
    @Option(
        names = ["-r", "--remoteRepository"], description = ["脚本文件远端依赖仓库 url"]
    )
    var remoteRepository: Array<String> = emptyArray()

    override fun run() {
        script = script.pathNormalize()
        val scriptFile = File(script)
        if (!scriptFile.exists()) {
            throw RuntimeException("脚本文件不存在：$script")
        }

        // 依赖 URL
        val libUrls = getLibFiles().toMutableList()

        // 远端依赖
        libUrls += getArtifactsUrls()

        // 本地依赖
        libUrls += libsDir.listFiles { file -> file.extension == "jar" }?.map { it } ?: emptyList()

        // 设置环境属性
        System.setProperty("kotlin.java.stdlib.jar", File(libsDir, "kotlin-stdlib-2.0.0.jar").absolutePath)
        System.setProperty("kotlin.java.reflect.jar", File(libsDir, "kotlin-reflect-2.0.0.jar").absolutePath)
        System.setProperty("kotlin.script.runtime.jar", File(libsDir, "kotlin-script-runtime-2.0.0.jar").absolutePath)

        // 执行依赖脚本
        val result = evalFile(scriptFile, libUrls)

        // 编译报告
        if (result.reports.isNotEmpty()) {
            println("\n\n编译报告：======================")
            result.reports.forEach {
                if (it.severity > ScriptDiagnostic.Severity.DEBUG) {
                    println(it.render())
                }
            }
            println("===========================\n")
        }

        // 执行结果
        if (result is ResultWithDiagnostics.Success) {
            when (val returnValue = result.value.returnValue) {
                is ResultValue.Error -> {
                    throw returnValue.error
                }

                is ResultValue.Unit, is ResultValue.Value -> println(returnValue)

                is ResultValue.NotEvaluated -> {
                    // 忽略
                }
            }
        }
    }

    /**
     * 获取用户指定的依赖文件
     */
    private fun getLibFiles(): List<File> {
        return libs.map {
            try {
                File(it)
            } catch (e: Exception) {
                throw RuntimeException("额外依赖路径[$it]解析失败：${e.message}")
            }
        }
    }


    /**
     *  远端依赖 URL
     */
    private fun getArtifactsUrls(): List<File> {
        if (artifacts.isNotEmpty()) {

            // 存储库
            val repositoryList = remoteRepository.map { toRemoteRepository(url = it) }
                .ifEmpty { MavenRepository.defaultRemoteRepository }

            return artifacts.flatMap {

                try {
                    val files = MavenRepository.download(
                        artifacts = it,
                        repositoryList = repositoryList,
                    )

                    files
                } catch (e: Exception) {
                    throw RuntimeException("下载远端依赖 $it 发生例外：${e.message}", e)
                }
            }
        }

        return emptyList()
    }
}
